package com.webex.ta.hydra.core.assertion;

import com.webex.ta.hydra.core.*;
import com.webex.ta.hydra.Constants;
import com.webex.ta.hydra.util.HydraUtils;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;
import java.io.ByteArrayInputStream;

import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.apache.xpath.objects.XObject;
import org.apache.xpath.XPathAPI;

/**
 * Author: Vegaz
 * Date: 2010-10-29
 * Time: 16:02:29
 */
public class XPathAssertion extends AbstractAssertion {

    private static final ParamDescriptor[] desc = new ParamDescriptor[2];

    static {
        desc[0] = new ParamDescriptor("xpath to test");
        desc[1] = new ParamDescriptor(ParamType.LIST, "use namespace", true,
                new String[]{Constants.TRUE, Constants.FALSE});
    }

    public ParamDescriptor[] getParamDescriptors(Command cmd) {
        return desc;
    }

    public void doAssertion(TestResult tr, AssertionResult ar, String... args) {
        String xpath = args[0];
        boolean namespaceAware = Constants.TRUE.equals(args[1]);
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        factory.setNamespaceAware(namespaceAware);

        try {
            DocumentBuilder db = factory.newDocumentBuilder();
            Document doc = db.parse(new ByteArrayInputStream(tr.getResponse().getBytes("UTF-8")));
            if (doc == null || doc.getDocumentElement() == null) {
                ar.setError(true);
                ar.setMessage("Document is null, probably not parsable");
            }

            NodeList nodeList = null;
            XObject xObject = XPathAPI.eval(doc, xpath);
            switch (xObject.getType()) {
                case XObject.CLASS_NODESET:
                    nodeList = xObject.nodelist();
                    break;
                case XObject.CLASS_BOOLEAN:
                    if (!xObject.bool()) {
                        ar.setFailure(true);
                        ar.setMessage("No Nodes Matched " + xpath);
                    }
                default:
                    ar.setFailure(true);
                    ar.setMessage("Cannot understand: " + xpath);
            }

            if (nodeList == null || nodeList.getLength() == 0) {
                ar.setFailure(true);
                ar.setMessage("No Nodes Matched " + xpath);
            }
        } catch (Exception e) {
            ar.setError(true);
            ar.setMessage(HydraUtils.printStackTraceToString(e));
        }
    }
}
